﻿using System.ComponentModel;
using System.Diagnostics;
using Microsoft.VisualBasic;

namespace System
{
  [DebuggerStepThrough]
  public static class ObjectExtensions
  {
    public delegate void VoidDelegate();

    public static byte ToByte(this object obj, byte defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToByte(obj);
      return defaultVal;
    }
    public static short ToInt16(this object obj, short defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToInt16(obj);
      return defaultVal;
    }
    public static int ToInt32(this object obj, int defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToInt32(obj);
      return defaultVal;
    }
    public static long ToInt64(this object obj, long defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToInt64(obj);
      return defaultVal;
    }
    public static float ToFloat(this object obj, float defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToSingle(obj);
      return defaultVal;
    }
    public static double ToDouble(this object obj, double defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToDouble(obj);
      return defaultVal;
    }
    public static bool ToBoolean(this object obj, bool defaultVal)
    {
      bool val = defaultVal;

      if (obj != null)
        if (bool.TryParse(obj.ToString(), out val))
          return val;

      return val;
    }

    public static byte ToByte(this object obj, byte? defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToByte(obj);
      return defaultVal.Val();
    }
    public static short ToInt16(this object obj, short? defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToInt16(obj);
      return defaultVal.Val();
    }
    public static int ToInt32(this object obj, int? defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToInt32(obj);
      return defaultVal.Val();
    }
    public static long ToInt64(this object obj, long? defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToInt64(obj);
      return defaultVal.Val();
    }
    public static float ToFloat(this object obj, float? defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToSingle(obj);
      return defaultVal.Val();
    }
    public static double ToDouble(this object obj, double? defaultVal)
    {
      if (Information.IsNumeric(obj)) return Convert.ToDouble(obj);
      return defaultVal.Val();
    }
    public static bool ToBoolean(this object obj, bool? defaultVal)
    {
      bool val = defaultVal.Val();

      if (obj != null)
        if (bool.TryParse(obj.ToString(), out val))
          return val;

      return val;
    }


    public static byte ToByte(this object obj)
    {
      return ToByte(obj, 0);
    }
    public static short ToInt16(this object obj)
    {
      return ToInt16(obj, 0);
    }
    public static int ToInt32(this object obj)
    {
      return ToInt32(obj, 0);
    }
    public static long ToInt64(this object obj)
    {
      return ToInt64(obj, 0);
    }
    public static float ToFloat(this object obj)
    {
      return ToFloat(obj, 0);
    }
    public static double ToDouble(this object obj)
    {
      return ToDouble(obj, 0);
    }
    public static bool ToBoolean(this object obj)
    {
      return ToBoolean(obj, false);
    }

    public static bool IsInteger(this object obj)
    {
      if (obj.IsNull()) return false;
      var val = 0;
      return int.TryParse(obj.ToString(), out val);
    }
    public static bool IsDouble(this object obj)
    {
      if (obj.IsNull()) return false;
      var val = 0.0;
      return double.TryParse(obj.ToString(), out val);
    }

    public static bool IsNull(this object obj)
    {
      return obj == null;
    }
    public static bool IsNotNull(this object obj)
    {
      return obj != null;
    }
    public static bool IsNull(this object obj, Action action)
    {
      if (obj == null)
        return true;

      action();
      return false;
    }
    public static bool IsNotNull(this object obj, Action action)
    {
      if (obj == null)
        return false;

      action();
      return true;
    }

    public static bool IsDBNull(this object obj)
    {
      return obj is DBNull;
    }

    public static T Safe<T>(this T obj) where T : new()
    {
      if (obj == null)
      {
        obj = new T();
      }

      return obj;
    }

    public static void With<T>(this T obj, Action<T> act)
    {
      act(obj);
    }

    public static bool Between<T>(this T actual, T lower, T upper) where T : IComparable<T>
    {
      return actual.CompareTo(lower) >= 0 && actual.CompareTo(upper) < 0;
    }

    public static T ConvertTo<T>(this object value, T defaultValue)
    {
      if (value != null)
      {
        var targetType = typeof(T);

        if (value.GetType() == targetType) return (T)value;

        var converter = TypeDescriptor.GetConverter(value);
        if (converter != null)
        {
          if (converter.CanConvertTo(targetType))
            return (T)converter.ConvertTo(value, targetType);
        }

        converter = TypeDescriptor.GetConverter(targetType);
        if (converter != null)
        {
          if (converter.CanConvertFrom(value.GetType()))
            return (T)converter.ConvertFrom(value);
        }
      }
      return defaultValue;
    }

    public static bool Try(this object obj, VoidDelegate del)
    {
      try
      {
        del.Invoke();
        return true;
      }
      catch (Exception ex)
      {
        ex.Log();
        return false;
      }
    }

  }
}